import json
import time

from common import md5, timeStamp
from fileOperate import fileExist, loadFromFile, writeToFile
from lock import SpinLock

class SplittedDict():
    '''
        在磁盘中分布式存储的一个字典
    '''
    _dir = ""

    def __init__(self, dir):
        self._dir = dir
    
    def insert(self, a):
        '''
            传入的参数 a 也是一个字典，这个函数将 a 和原字典合并
        '''
        buf = {}
        for i in a:
            b = md5(i)
            if b[:2] in buf:
                buf[b[:2]][b] = a[i]
            else:
                buf[b[:2]] = {b: a[i]}
        for i in buf:
            fnm = self._dir  + "/" + i + ".json"
            if fileExist(fnm):
                f = loadFromFile(fnm)
                f = json.loads(f)
            else:
                f = {}
            f.update(buf[i])
            f = json.dumps(f)
            writeToFile(fnm, f)

    def value(self, a):
        '''
            根据键查值
        '''
        fnm = self._dir + "/" + md5(a)[:2] + ".json"
        if not fileExist(fnm):
            return None
        f = loadFromFile(fnm)
        f = json.loads(f)
        return f[md5(a)]

    def __contains__(self, a):
        '''
            判断一个键是否在字典中
        '''
        fnm = self._dir + "/" + md5(a)[:2] + ".json"
        if not fileExist(fnm):
            return False
        f = loadFromFile(fnm)
        f = json.loads(f)
        return md5(a) in f

class SplittedList():
    '''
        在磁盘中分布式存储的一个列表
    '''
    _dir = ""

    def __init__(self, dir):
        self._dir = dir
    
    def insert(self, a):
        '''
            传入的参数 a 也是一个列表，这个函数将 a 和原列表合并
        '''
        buf = {}
        for i in range(len(a)):
            a[i] = md5(a[i])
            if a[i][:2] in buf:
                buf[a[i][:2]].append(a[i])
            else:
                buf[a[i][:2]] = [a[i]]
        for i in buf:
            buf[i] = list(set(buf[i])) # unique it
            fnm = self._dir  + "/" + i + ".json"
            if fileExist(fnm):
                f = json.loads(loadFromFile(fnm))
            else:
                f = []
            f += buf[i]
            f = list(set(f)) # unique
            writeToFile(fnm, json.dumps(f))

    def getBlock(self): # get some elements and delete it
        '''
            从列表中取出一部分并删除之
            返回一个列表
        '''
        hexi = list("0123456789abcdef")
        hexj = list("0123456789acbdef")
        __import__("random").shuffle(hexi)
        __import__("random").shuffle(hexj)
        for i in hexi:
            for j in hexj:
                fnm = self._dir + "/" + i + j + ".json"
                if not fileExist(fnm):
                    continue
                tmp = loadFromFile(fnm)
                tmp = json.loads(tmp)
                if tmp == []:
                    continue
                writeToFile(fnm, "[]")
                return tmp

    def __contains__(self, a):
        '''
            判断一个元素是否在列表中
        '''
        fnm = self._dir + "/" + md5(a)[:2] + ".json"
        if not fileExist(fnm):
            return False
        f = loadFromFile(fnm)
        f = json.loads(f)
        return md5(a) in f

class DICT():
    '''
        加了异步锁的在磁盘中分布式存储的一个字典
        封装了一些模板函数
    '''
    lock = None

    def __init__(self, dir):
        print("DICT dir =", dir)
        self.lock = SpinLock(SplittedDict(dir))

    def __getitem__(self, key):
        return self.lock.run(lambda x: x.value(key))
    
    def __setitem__(self, key, value):
        if isinstance(key, list):
            self.lock.run(lambda x: x.insert(dict(zip(key, value))))
        else:
            self.lock.run(lambda x: x.insert({key: value}))
    
    def __contains__(self, key):
        if isinstance(key, list):
            flg = True
            for i in key:
                flg = flg and self.lock.run(lambda x: i in x)
                if not flg: break
            return flg
        else:
            return self.lock.run(lambda x: key in x)

class LIST():
    '''
        加了异步锁的在磁盘中分布式存储的一个列表
        封装了一些模板函数
    '''
    lock = None

    def __init__(self, dir):
        print("LIST dir =", dir)
        self.lock = SpinLock(SplittedList(dir))
    
    def append(self, elem):
        if isinstance(elem, list):
            self.lock.run(lambda x: x.insert(elem))
        else:
            self.lock.run(lambda x: x.insert([elem]))

    def __iadd__(self, elem):
        self.append(elem)
    
    def __contains__(self, elem):
        if isinstance(elem, list):
            flg = True
            for i in elem:
                flg = flg and self.lock.run(lambda x: i in x)
                if not flg: break
            return flg
        else:
            return self.lock.run(lambda x: elem in x)

    def getBlock(self):
        return self.lock.run(lambda x: x.getBlock())
